iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
IT Operation

地端機房的三十天維運:開源服務封裝、GPU 節點守護與可稽核的變更管理系列 第 19 篇

Day 19|指標收集:把前十八天的取樣器接進同一個時間序列

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20261003/20141816OQeDX0kpTd.png

前情提要
截至 Day 18 為止,地端環境中的運算節點、儲存設備與災難復原演練都已具備可重複驗證的資料證據。然而,這些資料目前分散在四個獨立角落:Day 12 的 hw-sample.py 將溫度與記憶體寫入節點本機 JSON,Day 17 的 nas-audit.sh 輸出 Markdown 報告,Day 15 的 PVE check.sh 仰賴手動執行,Day 16 至 18 的 drills.jsonl 則各自散落在三個不同的程式碼倉庫中。

目前沒有任何單一介面能同時掌握 GPU 節點的熱浸潤(Thermal Soak)、NAS 儲存池與快照變化、PVE 叢集 HA 狀態,以及距離上一次還原演練成功究竟過了幾天。第三階段的核心任務就是從「分散取樣」邁向「統一觀測」,今天先完成指標收集,Day 20 再進行視覺化與告警建置。


一、現有指標盤點與監控現況

在著手導入監控系統前,先盤點前十八天累積的七種取樣來源及其儲存現況:

來源類型 目標設備 產生機制 輸出格式 取樣頻率 現況瓶頸
熱度與統一記憶體 DGX Spark 兩台 Day 12 hw-sample.py fsync JSONL 預設 3 秒一次 僅存於節點本機
主機記憶體防護 DGX Spark 兩台 Day 12 gb10-host-guard.py systemd journal 事件觸發 僅能事後翻查日誌
儲存池與快照 QNAP NAS 兩台 Day 17 nas-audit.sh Markdown 人工觸發 無法自動追蹤趨勢
磁碟與系統溫度 QNAP NAS 兩台 無 無 無 尚未納入收集
虛擬化叢集與 HA PVE 兩台 + QDevice Day 15 check.sh 指令文字輸出 人工觸發 無法歷史回溯
災難還原演練 三個程式庫 Day 16, 17, 18 演練腳本 drills.jsonl 每次演練產生 散落各專案目錄
異地雲端副本 GCS Bucket Day 18 offload-drill.sh drills.jsonl 每次上傳產生 同上

場域基礎設施狀態

  • 運算節點:兩台 DGX Spark 運行 vLLM、ComfyUI 與推論服務,先前尚未常駐 node_exporter,hw-sample.py 也未以 systemd daemon 形式背景化。
  • 虛擬化環境:PVE 叢集維持兩個運算節點搭配一台外部仲裁節點(QDevice),支援開立具備 Auditor 唯讀權限的 API Token。
  • 網路儲存:NAS 的 SNMP 設定需要加固。主 NAS 原配置為安全性較弱的 SNMPv3 noAuthNoPriv,次要 NAS 尚未啟用;本次統一部署提升為 authPriv 安全等級。
  • 收集端主機:獨立部署於 PVE 虛擬機(分配 2 vCPU、4 GB RAM、32 GB 儲存空間),避免監控服務與 NAS 儲存高度耦合,確保在儲存設備維護或停機演練時,監控主機仍可正常運作。

二、技術選型:Prometheus Pull 架構的工程優勢

在無既有歷史包袱的前提下,監控系統的選型主要考量兩項原則:連線架構(Who connects to whom) 與 儲存資源消耗。

為什麼選擇 Prometheus 的 Pull 模型?

  1. 節點配置解耦:Prometheus 採取由收集端定時主動抓取(Pull)各端點的 /metrics。被監控主機只需於本機暴露特定 HTTP 埠,完全不需感知收集端的 IP 或位置;未來收集端搬遷或擴展時,受控節點零改動。
  2. 防火牆規則極簡化:DGX Spark 節點上的防火牆(延續 Day 11 的加固原則),僅需單向開放 TCP 9100 給收集端 IP。
  3. 原生內建活性檢測:若目標主機崩潰、網路中斷或服務終止,Prometheus 的抓取狀態會立即轉為 up == 0,這項原語本身就是高可靠的心跳訊號,無須額外開發外部健康檢查機制。

與 VictoriaMetrics 的權衡

VictoriaMetrics 在資源消耗與壓縮率上表現極佳,適合大規模時序場景。但在此場域中,總活躍序列數約為 7,700 條(詳見第五節實測),Prometheus 容器常駐記憶體僅約 119 MiB。在此規模下,兩者的效能與記憶體差異並不顯著。選擇 Prometheus 的核心價值在於其生態系成熟度、Exporter 相容性,以及與 Grafana 銜接的高普及度。經容量精算後,本場域將資料保留期(Retention)設定為 90 天。


三、三類指標來源的整合架構

面對不同設備與業務指標,整合原則為:標準硬體與作業系統指標交由官方 Exporter,專用硬體特性與業務歷史則透過 node_exporter 的 Textfile Collector 進行擴充補足。

Textfile Collector 是一種簡潔可靠的通訊協議:任何背景工作只需原子性(Atomic Write)地將符合 Prometheus 格式的文字寫入 .prom 檔案,node_exporter 即可在下次抓取時對外暴露。

實作細節:暫存檔權限陷阱
使用 Python 的 tempfile.mkstemp 建立暫存檔時,預設檔案權限為 0600。若未做權限變更就直接原子替換(rename),以非 root 權限運行的 node_exporter 將無法讀取,導致 node_textfile_scrape_error 標記為 1。因此,腳本在替換檔案前均調用 fchmod 0644,並在 CI 測試中加入輸出檔案權限檢查。


1. DGX Spark:node_exporter 搭配硬體專用 Textfile

標準的 node_exporter 雖然具備 thermal_zone 與 /proc/meminfo 收集器,但無法捕捉本場域最關鍵的兩大致命故障模式:

  1. 熱浸潤(Thermal Soak):硬體死機往往不是因為瞬間峰值溫度,而是高溫持續停留的總時間(Day 12 實測顯示 417 秒的熱累積會觸發韌體級強制斷電)。
  2. 統一記憶體枯竭:在整合記憶體架構下,記憶體不足不會觸發標準 Linux OOM Killer,而是由核心日誌率先噴出 NV_ERR_NO_MEMORY,此訊號通常比系統 Livelock 早出現數十分鐘。

改寫自 Day 12 工具的 gb10-textfile.py,由 systemd timer 每 10 秒觸發一次,輸出包含管線健康狀態在內的 12 個關鍵指標,其中最關鍵的三項如下:

指標名稱 數據來源 監控目的
gb10_soak_seconds 核心溫度最高 thermal zone 在 ≥ 88 °C 的累積秒數 散熱預算消耗評估。Day 12 防護機制以 240 秒為上限,逾時即中止負載
gb10_nv_err_no_memory_total dmesg 中 NV_ERR_NO_MEMORY 的累計次數 統一記憶體 OOM 的唯一早期預警
gb10_hot 由取樣守護程式建立的 HOT 標記檔 提供給不可中斷推論/批次任務在階段間檢查的退避訊號
  • 狀態重置邏輯:Soak 計算屬於有狀態邏輯,狀態序列化於本地 JSON 檔案。若定時器中斷超過 60 秒,狀態自動歸零重算,避免計數混淆。
  • 權限最小化原則:DGX OS 啟用了 dmesg_restrict,一般使用者無法直接讀取核心日誌。本服務透過 systemd 指派專用系統帳號,僅給予單一 CAP_SYSLOG 權限,並配置 ProtectSystem=strict,僅開放指標目錄與暫存狀態目錄可寫。
  • DCGM Exporter 評估結果:實測 NVIDIA DCGM Exporter(ARM64 版本),在 GB10 架構下記憶體溫度回傳為 0,且無法取得傳統顯存佔用(因硬體為統一記憶體,需讀取系統級 /proc/meminfo)。因此目前維持以輕量腳本獲取溫度、功耗與利用率。

2. QNAP NAS:硬體走 SNMP v3,ZFS 儲存池走受限 SSH

之前場域內部測試有用過 SSH 遠端執行腳本獲取資料。但從安全縱深角度評估,監控收集端是整個網路中連通性最廣的節點,若其持有的 SSH 金鑰具備遠端 Shell 執行權限,一旦收集端遭受滲透,將連帶危及儲存核心。

因此進行責任分工重構:

  • 硬體與作業系統指標:透過嚴密的 SNMPv3 authPriv 唯讀查詢。
  • 進階儲存指標(ZFS 資料集與快照):保留 SSH 抓取,但金鑰配置 authorized_keys 嚴格限制來源 IP、強制限制執行單一指令且設定 no-pty。
[收集端 Prometheus]
       │
       ├──── SNMP v3 (authPriv, 161/UDP) ────► [QNAP NAS] (硬體狀態、SMART、風扇、溫度、磁碟池)
       │
       └──── SSH (受限金鑰, 唯讀 ZFS 指令) ─────► [QNAP NAS] (快照數量、佔用空間、資料集詳情)
收集途徑:SNMP(qnap_*) 收集途徑:受限 SSH Textfile(nas_*)
各磁碟狀態、溫度、SMART 完整屬性表 各 ZFS 資料集快照總數、最新/最舊快照時間
RAID 群組與儲存池容量、剩餘空間、健康狀態 排除 :init: 標籤後的實際快照佔用量
共享資料夾配額、WORM 不可變狀態、壓縮/去重旗標 依資料集名稱精確列出的 zpool 實際利用率
風扇轉速、CPU 核心溫度、記憶體總量與使用率 服務連線探測指標(nas_up)
韌體版本、服務開關(SSH/FTP/Telnet)、已裝套件

SNMP 設定與除錯實務經驗

  1. 加固協定選擇:在 QuTS hero 系統中,安全等級配置為 authPriv,認證採用 HMAC-SHA,加密採用 DES。密語長度須大於 8 碼以符合 net-snmp 規範。
  2. 告警邊界陷阱:
    • 若認證安全等級設定不合(例如設備端要求 authPriv,收集端誤用 authNoPriv),snmp_exporter 仍會回傳 HTTP 200 且 up == 1,但指標只包含 exporter 本身的計數,導致常規的 TargetDown 告警失靈。為此必須補上一條 NasSnmpNoData 規則檢查樣本數量。
    • 若通訊協定密鑰錯誤(如 SHA 對應 MD5),則 exporter 抓取會直接失敗,觸發 up == 0。

3. PVE 虛擬化叢集:pve-exporter 搭配專用唯讀權限

使用社群成熟的 prometheus-pve-exporter,透過 Proxmox VE 的 REST API 抓取 VM 運作狀態、節點資源利用率、儲存空間與叢集 Quorum 仲裁資訊。

  • 權限控管:建立專用帳號 prometheus@pve,在 PVE 根路徑僅賦予 PVEAuditor 唯讀角色,並簽發專用 API Token。權限憑證檔案存於收集端本機,權限設定為 0640,並鎖定容器使用者 GID 存取。
  • 序列去重注意:PVE API 每次查詢回傳的是整座叢集的狀態。若在 Prometheus 中同時抓取兩個 PVE 節點,會導致各節點重複回傳整座叢集的 VM 數據。因此在 PromQL 查詢聚合指標時,需固定帶入 instance 標籤過濾,避免統計數字翻倍。

4. 演練日誌時序化:從靜態 JSONL 到連續 SLO 觀測

Day 16 至 Day 18 的還原演練與雲端卸載腳本,原先會在各自倉庫產生 drills.jsonl。透過 drills-textfile.py 解析日誌,標準化不同模組間的欄位定義差異(例如統一整合 rto_s 與 rto),輸出包含成功狀態、RTO、RPO、傳輸頻寬以及 「距離上次成功還原時間戳」 的時序指標。

# 轉換後的演練指標範例
drill_last_rto_seconds{source="pve",label="d3-full"} 569
drill_last_rpo_seconds{source="pve",label="d3-full"} 784
drill_last_success_timestamp{source="cloud",label="restore-music-to-primary"} 1790898239

這項轉換使原本屬於「點狀事件」的演練紀錄,升級為可持續監看的「連續服務水準(SLO)」指標,能在儀表板上直觀呈現演練新鮮度。


四、防範靜默失效:文字檔收集器的活性檢測(Staleness Detection)

使用 Textfile Collector 最常見的架構隱患是,**取樣腳本已經當掉或定時任務失效,但舊的 .prom 檔案仍留在磁碟上。**此時 node_exporter 依然會定期讀取舊檔案端出數值,Prometheus 看到的是一條平緩正常的數值線,形成看似全綠燈的「靜默失效」。

為解決這種問題,所有取樣用的程式碼一律輸出帶有目前 Unix 時間戳的 *_last_run_timestamp 指標,並在 Prometheus 配置活性檢查警報規則:

# rules/staleness.yml
groups:
  - name: pipeline_staleness
    rules:
      - alert: Gb10TextfileStale
        expr: (time() - gb10_last_run_timestamp) > 120
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "DGX Spark 硬體取樣腳本已停止更新超過 2 分鐘"

      - alert: NasTextfileStale
        expr: (time() - nas_last_run_timestamp) > 600
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "NAS ZFS 取樣定時任務逾期未回報"

      - alert: NasSnmpNoData
        expr: scrape_samples_scraped{job="nas-snmp"} < 50
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "NAS SNMP 抓取異常,回傳指標過少(可能為 v3 認證協定不匹配)"
警報名稱 觸發條件 意涵與可能根因
TargetDown up == 0 持續 5 分鐘 目標主機宕機或網路中斷
Gb10TextfileStale 執行間隔超過 120 秒 systemd timer 異常或腳本執行掛起
NasTextfileStale 執行間隔超過 10 分鐘 Cron 排程未觸發或 SSH 通道異常
NasSnmpNoData 抓取樣本數小於 50 持續 5 分鐘 SNMPv3 加密/驗證協定配置錯誤
NasUnreachable nas_up == 0 持續 5 分鐘 儲存端 SSH 認證失敗或 ZFS 指令逾時

五、抓取頻率與容量規劃實測

監控系統本身的資源佔用必須具備精確的可預測性。以下為部署後的實際負載測量:

監控標的 端點數 抓取週期 平均單目標樣本數 每秒樣本產生率 (Samples/s)
DGX Spark node_exporter(含硬體擴充) 2 15s ~1,600 213.7
QNAP NAS SNMP 2 60s ~980 33.0
收集端本機(含 NAS/演練文字檔) 1 60s 879 14.7
PVE 叢集 pve-exporter 2 60s 343 11.4
Prometheus 自身效能指標 1 15s 885 59.0
總計 8 - 每輪 7,633 樣本 約 332 Samples/s

取樣間隔的設計考量

  • 運算節點(15 秒):GPU 節點的高溫預算上限為 240 秒,15 秒的間隔可確保在升溫區間內記錄到至少 15 個連續樣本點,足以精確刻畫曲線斜率;若拉長至 60 秒,則僅剩 4 個取樣點,無法及時分析熱累積特徵。
  • 儲存與虛擬化(60 秒):儲存池用量、快照與虛擬機狀態在極短時間內變動極小,採 60 秒頻率已能滿足監控需求,並可大幅降低 NAS 控制器的負載。

儲存空間與記憶體推算

根據 Prometheus TSDB 實務壓縮率,平均單一樣本佔用約 1.5 位元組。

每日儲存增量 ≈ 332 × 86,400 × 1.5 Bytes ≈ 43 MB / 天
90 天預估儲存 ≈ 43 MB × 90 ≈ 3.87 GB

六、資料驗證:端對端資料一致性檢驗

「指標顯示綠燈(up == 1),只代表 HTTP 埠有通,不代表取樣數值的真實性。」
為驗證 Prometheus 中的時間序列能誠實反映底層狀態,撰寫 verify.sh 自動化驗證腳本,由收集端同時拉取 Prometheus API 的最新值,並透過 SSH 執行來源端原生診斷指令進行比對。

各來源核心指標比對表

監控維度 測試目標 Prometheus 數值 原生指令輸出 對應底層指令 判定結果
GPU 溫度 DGX Spark 01 44 °C 44 °C nvidia-smi --query-gpu=temperature.gpu 一致(通過)
Thermal Zone DGX Spark 02 45 °C 45 °C cat /sys/class/thermal/thermal_zone*/temp 一致(通過)
可用記憶體 DGX Spark 01 23.97 GB 23.96 GB /proc/meminfo: MemAvailable 誤差小於 0.1%(通過)
ZFS 池使用率 主 NAS 26% 26% zpool list -H -o cap zpool1 一致(通過)
已用快照數 兩台 NAS 0 0 zfs list -t snapshot 一致(通過)
實體磁碟數 主 NAS 10 顆 10 顆 getsysinfo hdmodel 非空槽位數 一致(通過)
池可用空間 主 NAS 9.75 TB 9.75 TB zfs get -Hp available zpool1 誤差小於 0.01%(通過)
執行中 VM 數 PVE Node 01 5 台 5 台 qm list 執行狀態過濾 一致(通過)
HA 服務狀態 PVE 叢集 0 errors 0 errors ha-manager status 一致(通過)
最新演練 RTO 還原管線 569 秒 569 秒 drills.jsonl 最新紀錄 一致(通過)

驗證過程的硬體回饋
關於磁碟溫度指標校正,QNAP 專屬指令 getsysinfo hdtmp 需要 root 權限,非 root 帳號執行僅會回傳空值,因此硬體健康指標調整為透過 SNMP 讀取標準磁碟溫度與 SMART 屬性,避開權限過大的問題。
關於 SNMP 溫度感知機制,SNMP 回傳的 CPU 溫度來自 QTS 系統內部感測器且存在取樣快取,數值與底層 coretemp 封裝核心溫度存在微小溫差。此數值適合觀測長期溫升趨勢,但不宜直接與標準 Linux 伺服器的核心溫度做絕對值橫向比較。


2. 熱浸潤(Soak)保護機制動態重現

為驗證高溫保護機制在時序指標上的反應,透過矩陣乘法運算對 GPU 施加穩定負載,觀察持續高溫時指標的變化情形:

[測試進程時序]
11:17:49  通過冷卻門檻(GPU 43°C,Zone 44°C),啟動矩陣運算高負載
11:19:13  Thermal Zone 首次越過 88°C 臨界線
11:19:39  Prometheus 記錄到第一個非零 Soak 秒數(21s)
11:21:54  Zone 溫度達到峰值 95°C
11:23:09  防護守護程式判定連續超溫滿 240 秒,強制中止負載行程
11:23:10  負載終止,溫度於 1 秒內迅速回落至 85°C
11:23:24  Prometheus 下一次抓取,Soak 數值歸零
  溫度 (°C)
   100 │                                    [強制中止負載]
    90 │              ┌───────────────────────────┐
    80 │──────────────┘                           └────── (臨界門檻 88°C)
    70 │
    60 │
    50 │  ┌───────────┐
    40 └──┘           └──────────────────────────────────
       11:17         11:19                       11:23

測試驗證的關鍵發現:

  1. 曲線具備足夠解析度:以 15 秒為週期的抓取完整記錄了 15 個階梯式上升的點位,斜率與本機逐秒紀錄完全一致,能忠實還原升溫歷程。
  2. 抓取延遲對告警門檻的影響:當本機守護程式累計滿 240 秒並觸發中止時,Prometheus 接收到的數值為 227 秒。這是由於文字檔更新週期(10 秒)與 Prometheus 抓取週期(15 秒)疊加產生的相位差(最差約 25 秒延遲)。這意味著 Day 20 設定「Soak 接近超標」的告警門檻必須提前至 200~210 秒,否則告警將在防護程式介入後才響起。

https://ithelp.ithome.com.tw/upload/images/20261003/20141816vmgY3vnfCb.png


七、維運變更與標準部署流程

本篇所有操作均遵循最小權限與可回退原則,變更項目統整如下:

目標設備 變更項目與安全性設定
運算節點 (DGX Spark) 安裝 node_exporter;配置 gb10-textfile 服務與計時器(專用系統帳號,僅賦予 CAP_SYSLOG);防火牆僅放行收集端 IP 存取 9100/TCP。
網路儲存 (NAS) 啟用 SNMPv3 authPriv(SHA 驗證、DES 加密);配置 SSH 受限公鑰(指定來源 IP 與限制指令)。
虛擬化叢集 (PVE) 建立專用監控帳號 prometheus@pve,派發唯讀 Auditor Token。
監控收集端 (VM) 部署 Prometheus、snmp_exporter、pve-exporter 容器,配置自動化抓取與健全度規則。

快速部署步驟

# 1. 取得監控建置專案
git clone https://github.com/ivanusto/onprem-metrics && cd onprem-metrics

# 2. 設定目標清單與認證金鑰
cp prometheus/targets/gb10.yml.example prometheus/targets/gb10.yml
cp prometheus/targets/nas-snmp.yml.example prometheus/targets/nas-snmp.yml
cp prometheus/targets/pve.yml.example prometheus/targets/pve.yml
cp prometheus/pve.yml.example prometheus/pve.yml                # 填入 PVE API Token
cp prometheus/snmp-auth.yml.example prometheus/snmp-auth.yml    # 填入 SNMPv3 密碼

# 3. 權限收斂
sudo chown root:101 prometheus/pve.yml && sudo chmod 640 prometheus/pve.yml
sudo chown root:65534 prometheus/snmp-auth.yml && sudo chmod 640 prometheus/snmp-auth.yml

# 4. 驗證配置並啟動監控服務
promtool check config prometheus/prometheus.yml
docker compose up -d

# 5. 受控 GPU 節點端安裝 Exporter 與防火牆設定
sudo ./install-node.sh
sudo ufw allow proto tcp from <COLLECTOR_IP> to any port 9100

# 6. 執行全場域端對端數據驗證
PROM=http://localhost:9090 ./verify.sh \
  --gb10 user@192.168.10.131 --gb10 user@192.168.10.141 \
  --nas primary=ops@192.168.10.2 --nas secondary=ops@192.168.10.22 \
  --pve auditor@192.168.10.9 > verify-report.md

結語與明日預告

散落各處的取樣工具至此全數接入同一個 Prometheus 時間序列資料庫。透過 Pull 架構的解耦、最小權限防護設計,以及 Textfile 活性檢測機制,這次建立了一個兼顧安全性與即時性的監控基底。

有了這些標準化的時序數據,Day 20 將進入視覺化與預警階段,預期將利用 Grafana 打造整合運算節點 Soak 歷程、NAS 儲存池動態、PVE 叢集 Quorum 與災難還原間隔(距上次演練成功天數)的核心維運儀表板,並基於今日測試到的抓取延遲,調校出真正具備預警效力的告警規則。


相關資源與延伸閱讀


上一篇
Day 18|3-2-1 的最後一步:異地物件儲存、保留政策與冷熱資料成本精算
下一篇
Day 20|儀表板與告警,打造一個簡潔的單一面板
系列文
地端機房的三十天維運:開源服務封裝、GPU 節點守護與可稽核的變更管理 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言